package com.nlscan.ncomgateway.core.data.preference

import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.text.TextUtils
import androidx.preference.PreferenceManager
import com.nlscan.qdkit.common.core.app.App
import com.nlscan.ncomgateway.core.common.AppConfig
import com.nlscan.ncomgateway.core.common.AppState

/**
 * <pre>
 *  author: lin.qing
 *  time  : 2023/3/29
 *  desc  : 设置页面 Preferences 管理类
 * </pre>
 * !!!!!!!!!!!!!!!!!!!!!!!!! 成员变量定义规范要求 ！！！！！！！！！！！！！！！！！！
 * 2025-02-10 1. 类中的常量命名需要以 KEY_  开头，备份恢复需要根据该规则通过反射筛选出需要的字段；
 * ;2) 同样的，其中 getOutputMode/setXxx 方法也是需要保持一致
 */
@SuppressLint("StaticFieldLeak")
object SettingsPreferenceManager {

    /*
     * 作用
     * -- 1.用于找到 PreferenceView 控件
     * -- 2.与Preference 用到的 key 对应，即修改了这里的key，对应的 preference 也需要修改
     */

    //对应 Preference item
    const val KEY_CONNECT_CODE_CONFIG = "key_connect_code_config"
    const val KEY_CONNECT_CODE_TYPE = "key_connect_code_type"
    const val KEY_EXTRA_CONNECT_CODE = "key_extra_connect_code"

    /**
     * 输出模式
     */
    const val KEY_OUTPUT_MODE = "key_output_mode"

    /**
     * 模拟键输出
     */
    const val KEY_EMULATE_KEY_OUTPUT_SETTING = "key_key_output_setting"

    /**
     * 直接填充输出
     */
    const val KEY_FILL_OUTPUT_SETTING = "key_fill_output_setting"

    /**
     * 广播输出参数设置
     * todo 待复盘，当前将这些参数也写在这里
     */
    const val KEY_BROADCAST_OUTPUT_SETTING = "key_br_output_setting"
    const val KEY_BROADCAST_OUTPUT_ACTION = "key_br_output_action"

    //历史原因，key仍保留命名为xxx1
    const val KEY_BROADCAST_OUTPUT_EXTRA_RESULT = "key_br_output_extra_result1"
    const val KEY_BROADCAST_OUTPUT_EXTRA_DEVICE_NAME = "key_br_output_extra_dev_name"
    const val KEY_BROADCAST_OUTPUT_EXTRA_ADDRESS = "key_br_output_extra_address"
    const val KEY_BROADCAST_OUTPUT_EXTRA_SERIAL_NUMBER = "key_br_output_extra_serial_number"

    //int
    const val KEY_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE = "key_br_output_extra_barcode_type"
    const val KEY_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE_NAME = "key_br_output_extra_barcode_type_name"

    const val KEY_IP_OUTPUT_SETTING = "key_ip_output_setting"

    const val KEY_IP_OUTPUT_PROTOCOL = "key_ip_output_protocol"

    /**
     * 该值改为 hostname (包含ip和域名)
     */
    const val KEY_HTTP_OUTPUT_HOSTNAME = "key_ip_output_address"

    /**
     * 该值只适用于TCP和UDP、http固定80，https固定443
     */
    const val KEY_IP_OUTPUT_PORT = "key_ip_output_port"

    const val KEY_HTTP_OUTPUT_REQUEST_METHOD = "key_http_output_request_method"

    /**
     * http url的请求路径参数
     * e.g /search
     */
    const val KEY_HTTP_OUTPUT_REQUEST_PATH_PARAM = "key_http_output_request_path_param"


    const val KEY_TCP_CONNECT_STATE = "key_tcp_connect_state"
    const val KEY_UDP_LOCAL_PORT_STATE = "key_udp_local_port_state"

    /**
     *
     * -- 2025-02-10 备份恢复 KEY_IP_DATA_FORMAT_SWITCH对应的方法名可能不符合常规转换规则，因此需要特殊映射
     */
    const val KEY_IP_DATA_FORMAT_SWITCH = "key_ip_df_switch"
    const val KEY_IP_DATA_FORMAT_SETTING = "key_ip_df_setting"

    const val KEY_IP_DATA_FORMAT_USE_PACKET_HEADER = "key_ip_df_use_pkg_head"

    const val KEY_DATA_FORMAT_PREFIX = "key_df_prefix"
    const val KEY_DATA_FORMAT_SUFFIX = "key_df_suffix"
    const val KEY_DATA_FORMAT_FIELD_BARCODE = "key_df_field_barcode"
    const val KEY_DATA_FORMAT_FIELD_DEVICE_NAME = "key_df_field_dev_name"
    const val KEY_DATA_FORMAT_FIELD_DEVICE_ADDRESS = "key_df_field_dev_address"
    const val KEY_DATA_FORMAT_FIELD_SERIAL_NUMBER = "key_df_field_serial_number"
    const val KEY_DATA_FORMAT_FIELD_BARCODE_TYPE = "key_df_field_barcode_type"
    const val KEY_DATA_FORMAT_FIELD_BARCODE_TYPE_NAME = "key_df_field_barcode_type_name"
    const val KEY_DATA_FORMAT_FIELD_ASSIGNOR = "key_df_field_assignor"
    const val KEY_DATA_FORMAT_FIELD_SEPARATOR = "key_df_field_separator"

    const val KEY_SCAN_PROMPT_SETTING = "key_scan_prompt_setting"
    const val KEY_PREFIX_SUFFIX = "key_prefix_suffix"
    const val KEY_DATA_EDIT = "key_data_edit"

    /// 系统设置

    const val KEY_SHOW_IME = "key_show_ime"

    /**
     * 配对成功后应用自动退到后台
     */
    const val KEY_AUTO_HIDE_AFTER_PAIRING = "key_auto_hide_after_pairing"

    const val KEY_LAUNCH_APP_AFTER_PAIRING = "key_launch_app_after_pairing"

    const val KEY_SELECT_LAUNCH_APP = "key_launch_app"

    const val KEY_ADD_DEVICE_LIMIT = "key_add_device_limit"
    const val KEY_EXCEED_DEVICE_LIMIT_HANDLE = "key_exceed_device_limit_handle"

    const val KEY_ONE_CLICK_UNBINDING = "key_one_click_unbinding"
    const val KEY_ABOUT = "key_about"

    const val KEY_PWD_PROTECT = "key_pwd_protect";

    //备份恢复按钮
    const val KEY_BACKUP_RECOVERY = "key_backup_recovery"


    private var preferences: SharedPreferences? = null
        get() {
            if (field == null) {
                synchronized(SettingsPreferenceManager::class.java) {
                    if (field == null) {
                        if (context == null) {
                            context = App.getInstance()
                        }
                        //通过 PreferenceManager 来初始化
                        field = PreferenceManager.getDefaultSharedPreferences(context!!)
                    }
                }
            }
            return field!!
        }

    private var context: Context? = null

    private var editor: SharedPreferences.Editor? = null
        get() {
            if (field == null) {
                synchronized(SettingsPreferenceManager::class.java) {
                    if (field == null) {
                        if (context == null) {
                            context = App.getInstance()
                        }
                        //通过 PreferenceManager 来初始化
                        field = preferences!!.edit()
                    }
                }
            }
            return field!!
        }

    fun getConnectCodeType() = getInt(KEY_CONNECT_CODE_TYPE, AppConfig.DEFAULT_CONNECT_CODE_TYPE)

    fun setConnectCodeType(value: Int) = setInt(KEY_CONNECT_CODE_TYPE, value)

    fun getExtraConnectCode() = getString(KEY_EXTRA_CONNECT_CODE, "")

    fun setExtraConnectCode(value: String) = setString(KEY_EXTRA_CONNECT_CODE, value)


    //---------------------- 适配 Profile 的 API BEGIN ------------------- //

    /**
     * 返回值String 改为 Int
     */
    fun getOutputMode(): Int {
        return getString(
            KEY_OUTPUT_MODE,
            AppConfig.DEFAULT_OUTPUT_MODE.toString()
        ).toInt()
    }

    fun setOutputMode(mode: Int) {
        setString(KEY_OUTPUT_MODE, mode.toString())
    }

    fun isEmulateKeyOutputMode(): Boolean {
        return getOutputMode() == AppState.OUTPUT_MODE_EMULATE_KEY
    }

    fun isBroadcastOutputMode(): Boolean {
        return getOutputMode() == AppState.OUTPUT_MODE_BROADCAST
    }

    fun getBroadcastOutputAction() =
        getString(KEY_BROADCAST_OUTPUT_ACTION, AppConfig.DEFAULT_BROADCAST_OUTPUT_ACTION)

    fun setBroadcastOutputAction(value: String) =
        setString(KEY_BROADCAST_OUTPUT_ACTION, value)


    fun getBroadcastOutputExtraResult() =
        getString(
            KEY_BROADCAST_OUTPUT_EXTRA_RESULT,
            AppConfig.DEFAULT_BROADCAST_OUTPUT_EXTRA_RESULT
        )

    fun setBroadcastOutputExtraResult(value: String) =
        setString(KEY_BROADCAST_OUTPUT_EXTRA_RESULT, value)

    //---------------------- 适配 Profile 的 API END ------------------- //


    fun getBroadcastOutputExtraDeviceName() =
        getString(
            KEY_BROADCAST_OUTPUT_EXTRA_DEVICE_NAME,
            AppConfig.DEFAULT_BROADCAST_OUTPUT_EXTRA_DEVICE_NAME
        )

    fun setBroadcastOutputExtraDeviceName(value: String) =
        setString(KEY_BROADCAST_OUTPUT_EXTRA_DEVICE_NAME, value)


    fun getBroadcastOutputExtraAddress() =
        getString(
            KEY_BROADCAST_OUTPUT_EXTRA_ADDRESS,
            AppConfig.DEFAULT_BROADCAST_OUTPUT_EXTRA_ADDRESS
        )

    fun setBroadcastOutputExtraAddress(value: String) =
        setString(KEY_BROADCAST_OUTPUT_EXTRA_ADDRESS, value)

    fun getBroadcastOutputExtraSerialNumber() =
        getString(
            KEY_BROADCAST_OUTPUT_EXTRA_SERIAL_NUMBER,
            AppConfig.DEFAULT_BROADCAST_OUTPUT_EXTRA_SERIAL_NUMBER
        )

    fun setBroadcastOutputExtraSerialNumber(value: String) =
        setString(KEY_BROADCAST_OUTPUT_EXTRA_SERIAL_NUMBER, value)

    fun getBroadcastOutputExtraBarcodeType() =
        getString(
            KEY_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE,
            AppConfig.DEFAULT_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE
        )

    fun setBroadcastOutputExtraBarcodeType(value: String) =
        setString(KEY_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE, value)

    fun getBroadcastOutputExtraBarcodeTypeName() =
        getString(
            KEY_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE_NAME,
            AppConfig.DEFAULT_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE_NAME
        )

    fun setBroadcastOutputExtraBarcodeTypeName(value: String) =
        setString(KEY_BROADCAST_OUTPUT_EXTRA_BARCODE_TYPE_NAME, value)

    fun getIpOutputProtocol() = getString(
        KEY_IP_OUTPUT_PROTOCOL,
        AppConfig.DEFAULT_IP_OUTPUT_PROTOCOL
    )

    fun setIpOutputProtocol(value: String) = setString(KEY_IP_OUTPUT_PROTOCOL, value)

    fun getIpOutputHostname() =
        getString(
            KEY_HTTP_OUTPUT_HOSTNAME, ""
        )

    fun setIpOutputHostname(value: String) =
        setString(KEY_HTTP_OUTPUT_HOSTNAME, value)

    fun getIpOutputPort() =
        getString(
            KEY_IP_OUTPUT_PORT,
            AppConfig.DEFAULT_IP_OUTPUT_PORT
        )

    fun setIpOutputPort(value: String) =
        setString(KEY_IP_OUTPUT_PORT, value)

    fun getHttpOutputRequestMethod() =
        getString(KEY_HTTP_OUTPUT_REQUEST_METHOD, AppConfig.DEFAULT_HTTP_OUTPUT_REQUEST_METHOD)

    fun setHttpOutputRequestMethod(value: String) =
        setString(KEY_HTTP_OUTPUT_REQUEST_METHOD, value)

    fun getHttpOutputRequestPathParam() =
        getString(KEY_HTTP_OUTPUT_REQUEST_PATH_PARAM, "")

    fun setHttpOutputRequestPathParam(value: String) =
        setString(KEY_HTTP_OUTPUT_REQUEST_PATH_PARAM, value)

    fun isIpDataFormatOpen() =
        getBoolean(
            KEY_IP_DATA_FORMAT_SWITCH,
            false
        )

    fun setIpDataFormatOpen(value: Boolean) {
        setBoolean(KEY_IP_DATA_FORMAT_SWITCH, value)
    }

    fun isIpDataFormatUsePacketHeader() =
        getBoolean(KEY_IP_DATA_FORMAT_USE_PACKET_HEADER, true)

    fun setIpDataFormatUsePacketHeader(enable: Boolean) {
        setBoolean(KEY_IP_DATA_FORMAT_USE_PACKET_HEADER, enable)
    }

    fun getDataFormatPrefix() =
        getString(KEY_DATA_FORMAT_PREFIX, "")

    fun setDataFormatPrefix(value: String) =
        setString(KEY_DATA_FORMAT_PREFIX, value)

    fun getDataFormatSuffix() =
        getString(KEY_DATA_FORMAT_SUFFIX, "")

    fun setDataFormatSuffix(value: String) =
        setString(KEY_DATA_FORMAT_SUFFIX, value)

    fun getDataFormatBarcodeField() =
        getString(
            KEY_DATA_FORMAT_FIELD_BARCODE,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_BARCODE
        )

    fun setDataFormatBarcodeField(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_BARCODE, value)

    fun getDataFormatDeviceNameField() =
        getString(
            KEY_DATA_FORMAT_FIELD_DEVICE_NAME,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_DEVICE_NAME
        )

    fun setDataFormatDeviceNameField(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_DEVICE_NAME, value)

    fun getDataFormatDeviceAddressField() =
        getString(
            KEY_DATA_FORMAT_FIELD_DEVICE_ADDRESS,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_DEVICE_ADDRESS
        )

    fun setDataFormatDeviceAddressField(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_DEVICE_ADDRESS, value)

    fun getDataFormatSerialNumberField() =
        getString(
            KEY_DATA_FORMAT_FIELD_SERIAL_NUMBER,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_SERIAL_NUMBER
        )

    fun setDataFormatSerialNumberField(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_SERIAL_NUMBER, value)

    fun getDataFormatBarcodeTypeField() =
        getString(
            KEY_DATA_FORMAT_FIELD_BARCODE_TYPE,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_BARCODE_TYPE
        )

    fun setDataFormatBarcodeTypeField(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_BARCODE_TYPE, value)

    fun getDataFormatBarcodeTypeNameField() =
        getString(
            KEY_DATA_FORMAT_FIELD_BARCODE_TYPE_NAME,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_BARCODE_TYPE_NAME
        )

    fun setDataFormatBarcodeTypeNameField(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_BARCODE_TYPE_NAME, value)


    fun getDataFormatFieldAssignor() =
        getString(
            KEY_DATA_FORMAT_FIELD_ASSIGNOR,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_ASSIGNOR
        )

    fun setDataFormatFieldAssignor(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_ASSIGNOR, value)

    fun getDataFormatFieldSeparator() =
        getString(
            KEY_DATA_FORMAT_FIELD_SEPARATOR,
            AppConfig.DEFAULT_DATA_FORMAT_FIELD_SEPARATOR
        )

    fun setDataFormatFieldSeparator(value: String) =
        setString(KEY_DATA_FORMAT_FIELD_SEPARATOR, value)


    fun isAutoHideAfterPairing() =
        getBoolean(
            KEY_AUTO_HIDE_AFTER_PAIRING,
            false
        )

    fun setAutoHideAfterPairing(value: Boolean) =
        setBoolean(KEY_AUTO_HIDE_AFTER_PAIRING, value)


    fun isLaunchAppAfterPairing() =
        getBoolean(
            KEY_LAUNCH_APP_AFTER_PAIRING,
            false
        )

    fun setLaunchAppAfterPairing(value: Boolean) =
        setBoolean(KEY_LAUNCH_APP_AFTER_PAIRING, value)

    fun getAddDeviceLimit() =
        getString(KEY_ADD_DEVICE_LIMIT, AppConfig.DEFAULT_ADD_DEVICE_LIMIT.toString()).toInt()

    //提供给备份恢复使用
    fun setAddDeviceLimit(value: Int) =
        setString(KEY_ADD_DEVICE_LIMIT, value.toString())

    fun getExceedDeviceLimitHandle() =
        getString(
            KEY_EXCEED_DEVICE_LIMIT_HANDLE,
            AppConfig.DEFAULT_EXCEED_DEVICE_LIMIT_HANDLE.toString()
        ).toInt()

    fun setExceedDeviceLimitHandle(value: Int) =
        setString(KEY_EXCEED_DEVICE_LIMIT_HANDLE, value.toString())


    // 添加方法

    fun getExtraConnectCodeList(): MutableList<String> {
        val codeStr = getExtraConnectCode()
        if (TextUtils.isEmpty(codeStr)) {
            return mutableListOf()
        }
        return convertToExtraConnectCodeList(codeStr)
    }

    fun convertToExtraConnectCodeList(value: String): MutableList<String> {
        val list = value.split(";")
        val resultList = mutableListOf<String>()
        for (item in list) {
            if (item.isNotEmpty()) {
                resultList.add(item)
            }
        }
        return resultList
    }

    fun setExtraConnectCodeList(list: MutableList<String>) {
        setExtraConnectCode(convertToExtraConnectCodeStr(list))
    }

    fun convertToExtraConnectCodeStr(list: MutableList<String>): String {
        var codeStr = ""
        for (index in list.indices) {
            if (index == list.size - 1) {
                codeStr += list[index]
            } else {
                codeStr += "${list[index]};"
            }
        }
        return codeStr
    }


    fun isTcpOutputMode() =
        AppState.IP_OUTPUT_PROTOCOL_TCP == getIpOutputProtocol()

    fun isHttpOrHttpsOutputMode(): Boolean {
        val ipProtocol = getIpOutputProtocol()
        return AppState.IP_OUTPUT_PROTOCOL_HTTP == ipProtocol
                || AppState.IP_OUTPUT_PROTOCOL_HTTPS == ipProtocol
    }


    // 2、实现 get/set 接口

    private fun getString(key: String?, defaultValue: String): String {
        return preferences?.getString(key, defaultValue)!!
    }

    private fun setString(key: String?, value: String?) {
        editor?.putString(key, value)
        editor?.commit()
    }

    private fun getBoolean(key: String?, defaultValue: Boolean): Boolean {
        return preferences?.getBoolean(key, defaultValue)!!
    }

    private fun setBoolean(key: String?, value: Boolean) {
        editor?.putBoolean(key, value)
        editor?.commit()
    }

    private fun getInt(key: String, defaultValue: Int): Int {
        return preferences?.getInt(key, defaultValue)!!
    }

    private fun setInt(key: String, value: Int) {
        editor?.putInt(key, value)
        editor?.commit()
    }

}